Formularze wydruków WINSCRIPT © DELTA

SPIS TREŚCI

SPIS TREŚCI	1
Wstęp	3
1. Parametry początkowe, nagłówek i stopka formularza	3
2. Strony formularza	4
3. Stałe kolorów	5
4. Polecenia, definicje obiektów	5
5. Wykaz poleceń i obiektów.	6
Czcionka	6
Tekst	6
Linia tekstu	6
Zmiana pozycji pisaka	7
Cofnięcie pisaka	7
Przesunięcie współrzędnych	7
Pole tekstowe	7
Pole danych	8
Ramka	8
Prostokąt wypełniony	8
Grafika	9
Linia	9
Etykieta	9
Powtórzenie	9
Dołączenie zewnętrznego pliku	10
Definicja procedury	11
Wywołanie procedury	11
Powtórzenie procedury	12
Komunikat tekstowy	12
6. Obliczenia w formularzach	13
Wstęp.	13
Wyrażenia typu tekstowego	13
Wyrażenia typu liczbowego	13
Zmienne predefiniowane	14
Zmienne	14
Funkcje tekstowe i matematyczne	15
7. Odwołania do obiektów	16
8. Instrukcje warunkowe	17
9. Obsługa tabel tekstowych (raporty wielostronicowe)	18
Wprowadzenie	18
Przekazywanie danych do raportu.	19
Definicja i wywołanie linii seryjnej	19
Zakończenie	21
10. Dostęp do baz danych BDE.	21
Wstęp	21
Otwarcie bazy danych	21
Dostęp do pól tabeli	22
Operacje na tabeli	22
Zapytania warunkowe	23
Zapytania sparametryzowane	23
11. Informacje dla programistów	25
Wstęp	25
Użytkowanie komponentu	25
Przykładowy program	26

Wstęp

© DELTA Informatyka-Oprogramowanie Tomasz Waraksa, Gdynia, 1999-2000

Formularze wydruków obslugiwane przez komponent TScriptPrinter są plikami tekstowymi ASCII kodowanymi w standardzie Windows 1250. Składają się z szeregu słów kluczowych definiujących parametry, wygląd i zawartość wydruku. W formularzu można umieszczać komentarze - należy je zawsze rozpoczynać znakiem średnika ;

Wielkość liter w słowach kluczowych nie gra roli - do ich pisania można używać tak dużych, jak i małych liter. Wszelkie spacje na początku i na końcu linii poleceń są pomijane, zatem przy tworzeniu formularza można używać wcięć poprawiających jego przejrzystość i czytelność. Spacje w liniach tekstowych są oczywiście interpretowane i drukowane dosłownie.

Współrzędne pojawiające się w arkuszach domyślnie wyrażone są w milimetrach. Możliwe jest jednak używanie współrzędnych wyrażonych w calach lub pixelach – aktualnie używaną jednostkę miary można zmienić poleceniem Measure omówionym dalej. Przy określaniu współrzędnych dozwolone jest podawanie również ułamkowych części (w zasadzie precyzja jest dowolnie dokładna) – np.10.25 mm. We wszystkich wyrażeniach do oddzielenia części ułamkowej używać należy wyłącznie kropki dziesiętnej. 

1.	Parametry początkowe, nagłówek i stopka formularza
Formularz rozpoczyna się poleceniem

NAME=<nazwa formularza>

Podajemy w nim opis formularza. Polecenie to można pominąć, aczkolwiek nie jest to zalecane (parametr NAME może być w przyszłości wykorzystywany przez inne komponenty i moduły).

Kolejne linie formularza (aż do wystąpienia definicji pierwszej strony) to sekcja definicji. Umieszczamy w niej ogólne parametry wydruku oraz definicje wszystkich obiektów, które mają być gotowe i dostępne już w momencie rozpoczęcia drukowania pierwszej strony. Poza parametrami definiującymi ogólny wygląd formularza mogą się tu znaleźć definicje procedur, procedury inicjujące zmienne, zapytania SQL przygotowujące tabele z danymi itp. 

Formularz kończy się słowem kluczowym

END

Po słowie tym możemy wpisać dowolny tekst – np. opisy pól i procedur użytych w formularzu. Nie będą one analizowane ani drukowane. 

W części definicyjnej formularza można określić następujące parametry wydruku:

TRANSPARENT - powoduje, że pola tekstowe i ramki są "przezroczyste" - np. tekst umieszczony na prostokącie o kolorze żółtym będzie również miał tło żółte.

MEASURE=<kod_jednostki_miary>  to definicja jednostki miary używanej w formularzu. Jeżeli nie podamy jej jawnie, program domyślnie przyjmie milimetry. Dozwolone wartości to MM, INCH oraz PIX (odpowiednio milimetry, cale i piksele).

NOFILL - nie wypełniaj kolorowych prostokątów. Jeżeli w formularzu znajduje się polecenie wydrukowania wypełnionego prostokąta ale w nagłówku znajduje się to polecenie, program wydrukuje tylko ramkę tego prostokąta. Jest to prosty sposób na zwiększenie szybkości wydruku i zmniejszenie zużycia atramentu lub tonera – ale odbywa się to kosztem estetyki wydruków! 

FORM=<kod_rozmiaru_kartki>   to definicja rozmiaru papieru użytego do druku. Domyślnie jest to A4. Można tu podać następujące kody:  A3, A4, A5, A6, B5, Letter, Legal, FanFold (12”). Dodatkowo zdefiniowane są stałe dla standardowych kopert:  C5, C6, DL.

LANDSCAPE  - wymusza poziomą orientację wydruku

W przypadku raportów wielostronicowych w sekcji definicji warto zdefiniować nagłówek i stopkę wspólną dla wszystkich drukowanych stron formularza. W tym celu należy w formularzu stworzyć sekcje:

HEADER <wysokość>
. i tu zawartość nagłówka – zwykłe polecenia druku
ENDHEADER

oraz

FOOTER <wysokość>
. i tu zawartość stopki – zwykłe polecenia druku
ENDFOOTER

Zdefiniowane w ten sposób nagłówki i stopki będą automatycznie drukować się na wszystkich stronach wydruku. Nagłówek i stopka domyślnie są puste i zapewniają jedynie, że określona parametrem <wysokość> część kartki na dole i na górze nie będzie dostępna do drukowania. Jeśli chcesz oddzielić je od strony – np. poziomą linią, sam musisz umieścić w definicji nagłówka i stopki polecenie wydrukowania linii o odpowiednich parametrach. Ważne jest, że wszelkie współrzędne używane w definicji stron formularza automatycznie przesuwane są w dół o wysokość nagłówka (jeśli taki został zdefiniowany) – nie musimy więc korygować ich, jeśli wstawiliśmy nagłówek do już istniejącego formularza. Współrzędne używane we wnętrzu nagłówka oraz stopki są współrzędnymi względnymi – względem lewego górnego narożnika nagłówka lub stopki. Dzięki temu projektując nagłówek nie musisz zastanawiać się, jakie mogą być rozmiary papieru użytego do wydrukowania raportu.

W najprostszym kształcie nagłówek może zawierać polecenia wydrukowania tekstów i ewentualnie pól danych jak nazwa firmy itp. Więcej swobody możemy uzyskać używając w nagłówkach i stopkach omówionych dalej instrukcji warunkowych oraz zmiennych predefiniowanych. Pozwala to np. na drukowanie w nagłówku numeru strony, daty wydruku, wydrukowanie stopki z pominięciem pierwszej strony itp. Wszystkie te możliwości staną się oczywiste po zapoznaniu z dalszą częścią instrukcji.

Jak już wspomniano, w sekcji definicji można umieścić definicje zmiennych globalnych oraz przeprowadzić ewentualne wymagane przez dalej wywoływane procedury obliczenia arytmetyczne, operacje na polach tekstowych i na bazach danych. Umieszczenie takich poleceń w definicji którejkolwiek ze stron może czasem nie przynieść pożądanego efektu – gdyż nasza strona z powodu np. instrukcji warunkowych może nigdy nie być zanalizowana! Polecenia zawarte w sekcji definicji zostaną natomiast wykonane zawsze – i to przed rozpoczęciem analizowania kolejnych stron formularza.

2. Strony formularza
Kolejne strony zapisane są w sekcjach rozpoczynających się słowem PAGE:

PAGE <lm,gm,pm,dm>

Nawet jeśli formularz składa się tylko z jednej strony, należy umieścić w nim polecenie PAGE. Podając wartości lm, pm, dm, gm możemy określić wielkość marginesów (czyli ustalić obszar strony dostępny do druku). Wartości te oznaczają odpowiednio lewy margines, górny margines, prawy margines, dolny margines. Badanie osiągnięcia końca strony należy do kompetencji programisty – kolejna strona formularza jest tworzona poprzez użycie słowa PAGE, możliwe jest też powtórzenie drukowania zadanej strony w przypadku raportów wielostronicowych.  Wyjątkiem jest umieszczenie w formularzu bloków zwykłego tekstu  – w tym przypadku program automatycznie sprawdza, czy następna drukowana linia zmieści się na stronie (uwzględniając rezerwację miejsca na ewentualną stopkę). Jeśli linia nie zmieści się na stronie, program automatycznie tworzy kolejną stronę wydruku, umieszcza na niej zdefiniowany w skrypcie nagłówek i stopkę, po czym kontynuuje drukowanie linii. Jest to wygodne przy drukowaniu np. plików tekstowych. 

Dozwolone jest użycie samego słowa PAGE bez podania przesunięć – domyślnie zostaną one ustawione na 0. Można również podać tylko lewy i górny margines – bez określania prawego i dolnego.

Nie ma potrzeby kończenia definicji strony jakimkolwiek poleceniem. Wystąpienie kolejnego polecenia PAGE automatycznie zamyka poprzednią stronę, podobnie jest przy napotkaniu polecenia END kończącego analizę formularza.

Jak przed chwila wspomniano, w formularzu można użyć specjalnego polecenia: 

REPEATPAGE <nr_strony>

Służy ono do powtórnego zanalizowania i umieszczenia na wydruku strony o zadanym numerze. Najprostszym zastosowaniem tego polecenia jest wymuszenie wydrukowania określonej liczby egzemplarzy wydruku. W celu wygenerowania trzech egzemplarzy np. faktury – bez potrzeby ustawiania ilości kopii przez użytkownika w oknie wydruku – wystarczy na końcu strony formularza (przed słowem END) umieścić polecenie:

IF {EVAL PAGE<3} REPEATPAGE 1

Polecenie to sprawdza, czy numer bieżącej strony jest równy 3. Jeśli tak nie jest, powtarza drukowanie strony, co jednocześnie zwiększa numer aktualnej strony o 1. Budowa tego polecenia stanie się jaśniejsza po zapoznaniu się z dalszym ciągiem niniejszej instrukcji. Dopiero po wydrukowaniu trzeciej strony warunek nie będzie już spełniony i strona nie zostanie więcej wydrukowana. W miejsce stałej liczbowej 3 można rzecz jasna wstawić pole danych wypełniane przez użytkownika – wtedy to on będzie miał wpływ na generowaną liczbę kopii... Proponujemy wtedy konstrukcję:

SET IleEgz = EVAL [1]
IF {EVAL IleEgz>10} SET IleEgz = EVAL 1
IF {EVAL IleEgz<1} SET IleEgz = EVAL 1
IF {EVAL [PAGE]<[1]} REPEATPAGE 1

Dodatkowe linie z warunkami zabezpieczają nas przed podaniem przez użytkownika liczby kopii równej zero lub większej od 10. 

3. Stałe kolorów 
W definicji pól często występuje parametr kolor. Do określania kolorów można posługiwać się stałymi tekstowymi analogicznymi do stałych kolorów w Delphi: 

BLACK	, MAROON, GREEN, OLIVE, NAVY, PURPLE, TEAL, GRAY, SILVER, RED, LIME, BLUE, FUCHSIA, AQUA, WHITE

lub też stałymi liczbowymi (dozwolony zapis dziesiętny lub szesnastkowy, gdzie ciąg znaków szesnastkowych poprzedzony jest znakiem $). Odcienie szarości łatwo uzyskać podając jako kolor stopień jasności – w skali od 0 (czarny) do 255 (biały) – wpisujemy wówczas w miejsce koloru predefiniowaną stałą SHADE<stopień>, np. SHADE240, SHADE75, SHADE250.

4. Polecenia, definicje obiektów
W formularzu można umieścić różne obiekty do wydruku oraz wydać polecenia modyfikujące proces druku. 

Definicja drukowanego obiektu ma ogólną budowę postaci:

   <typ_obiektu> <NAME nazwa>=<parametry>|<parametry>|<parametry> .....

Parametry oddzielane są pionową kreską. Często parametr również składa się z kilku wartości (np. współrzędne albo definicja czcionki) - wówczas wartości te oddzielamy przecinkami.

Linia polecenia ma ogólną budowę postaci:

   <polecenie> <parametry>,<parametry>,<parametry> .....

Parametry oddzielane są przecinkami. W wielu poleceniach pojawiają się współrzędne. Można je określić na stałe, wpisując po prostu odpowiednie wartości liczbowe, można też współrzędne wyliczać dynamicznie w trakcie analizowania skryptu – używając wyrażeń arytmetycznych zawierających zmienne i pola danych. Może się to przydać np. w wydruku dowodu księgowego, który raz ma jedną a innym razem sześć pozycji – przy użyciu współrzędnych wyliczanych z wyrażeń tabelka pozycji dowodu może zmieniać swą wysokość w zależności od ilości tych pozycji! Podobnie pole na podpis wystawcy dokumentu zawsze może znajdować się 15 mm poniżej tabelki – i przesuwać się wraz ze zmianą jej wysokości! 

Nazwa obiektu jest opcjonalna – należy ją podać jedynie wtedy, gdy inne obiekty mają potem odwoływać się do parametrów naszego obiektu (jak jego współrzędne czy wymiary). Przykładowo na stronie mogą znaleźć się dwie ramki o tej samej szerokości. Warto w poleceniu drukowania drugiej ramki odwołać się do szerokości pierwszej ramki – jeżeli zmienimy szerokość pierwszej ramki, druga zostanie zmieniona automatycznie! Więcej szczegółów na ten temat w punkcie 6. Odwołania do obiektów.

5. Wykaz poleceń i obiektów.
Czcionka
FONT - definiuje domyślną czcionkę dla następujących po niej obiektów. Składnia:

	FONT=<nazwa>,<rozmiar>,<styl>,<kolor_czcionki>    np.

	FONT=Arial CE,8
	FONT=Tahoma,10,BU,RED

Jeśli nie zmienimy właściwości obiektu FONT używając powyższego polecenia, domyślnie przyjęta będzie czcionka MS SANS SERIF 10 pkt. w kolorze czarnym. W wielu obiektach czcionkę można zdefiniować indywidualnie dla konkretnego obiektu – taka definicja czcionki ma większy priorytet niż definicja czcionki domyślnej! Czcionka zdefiniowana poleceniem FONT obowiązuje dla wszystkich następujących po nim obiektów aż do następnego polecenia FONT. Pole STYL może przyjmować wartości: B (bold), I (italic), U (underline), S (strikeout) albo złożenia tych wartości, np. BI  albo  BUS. 

Tekst
TEXT x,y

rozpoczyna blok zwykłego tekstu, umożliwiając jednocześnie określenie pozycji początkowej pisaka dla tekstu. Po wywołaniu tego polecenia program drukuje następujące po nim linie dosłownie (choć istnieje możliwość umieszczania w tych liniach pól tekstowych, pól danych oraz zmiennych) – czyli nie próbuje analizować ich jako poleceń formularza. 

Blok tekstu należy koniecznie zakończyć poleceniem 

ENDTEXT

Linia tekstu
Linia tekstu to najprostszy drukowany obiekt. Może pojawić się w obrębie bloku tekstu ograniczonego omówioną wyżej parą poleceń TEXT i ENDTEXT. Nie wymaga żadnego określenia typu pola – w formularzu po prostu wystarczy napisać treść, którą chcemy wydrukować.  Każda linia drukowana jest dosłownie – włącznie z liniami pustymi. Pomijane są jedynie linie komentarzy zaczynające się od średnika ;

Pisanie rozpoczyna się domyślnie od punktu początkowego zadanego omówioną wcześniej komendą TEXT – współrzędna X jest traktowana jako margines, współrzędna Y jako współrzędna pierwszej drukowanej linii. Następna linia automatycznie zostanie wydrukowana odpowiednio niżej. Do drukowania tekstu używane są atrybuty podane w ostatniej komendzie FONT. 

Poza zwykłym tekstem w linii tekstu można również umieszczać kody pól danych automatycznie wypełniane przez program właściwymi wartościami, oraz wyrażenia tekstowe i arytmetyczne. W celu umieszczenia w linii tekstowej pola danych należy podać jego numer ujęty w nawiasy klamrowe, np.

adr.zam. [101] ul.[102]
         [103]

Aby w linii tekstowej umieścić wyrażenie, będące działaniem na grupie pól, należy linię wpisać w formie wyrażenia tekstowego lub arytmetycznego, o czym szerzej w punkcie 5.
	
	Zmiana pozycji pisaka
POS=x,y     np.
POS=10,15
	
Polecenie to działa tylko w bloku tekstowym, służy do zmiany aktualnej pozycji pisaka. Można nim zdefiniować nowe położenie pisaka – wszystkie następujące po nim linie tekstu będą drukowane z marginesem równym podanej współrzędnej X oraz w kolejnych liniach poczynając od współrzędnej Y.

	Cofnięcie pisaka
BACK
	
Polecenie to działa tylko w bloku tekstowym, służy do cofnięcia pisaka do poprzedniej linii. Po wydrukowaniu linii tekstu pisak jest automatycznie przesuwany do następnej linii (o wartość wynikającą z aktualnego rozmiaru czcionki). Wywołanie polecenia BACK spowoduje powrót do poprzedniej linii. 

	Przesunięcie współrzędnych
DX=<wartość>
DY=<wartość> 

to korekta położenia obiektów. Wszystkie współrzędne użyte od momentu zdefiniowania wartości DX i DY zostaną skorygowane o te wartości. Można używać zarówno wartości dodatnich, jak i ujemnych. Jest to najszybszy sposób na przesunięcie grupy elementów w pionie lub w poziomie bez potrzeby poprawiania ich indywidualnych współrzędnych. Przesunięcie obowiązuje do momentu wystąpienia następnej definicji przesunięcia. Aby zlikwidować przesunięcie, należy wpisać polecenia DX=0 oraz DY=0. Od tego momentu współrzędne obiektów będą traktowane dosłownie (uwzględniając jedynie bezwzględne przesunięcie zdefiniowane dla całej strony w nagłówku strony PAGE).

Pole tekstowe
T=<współrzędne>,<wyrównanie lub szerokość>,<kąt obrotu>|<tekst>|<czcionka>  np.

	 T=10,20|FAKTURA VAT|Arial CE,16,B,BLUE
	 T=10,20,40|STR [1]
	 T=10,20,40X|STR [1]
	 T=10,20,R|STR [2]
	 T=10,20,L,90|STR [3]

Pierwszy przykład – to tekst umieszczony w punkcie [10,20] mm względem lewego górnego narożnika kartki. Wydrukowany zostanie tekst FAKTURA VAT, a użyta będzie czcionka Arial CE o rozmiarze 16 punktów, pogrubiona, w kolorze niebieskim. W drugim przykładzie pojawił się parametr szerokość – nie jest on wymagany. Podanie tego parametru sprawia, że tekst jest zawijany do następnych linii jeśli jego szerokość jest większa niż podana. W trzecim przykładzie parametr szerokość został uzupełniony o literę X, oznaczającą polecenie obcięcia nadmiarowego tekstu, gdy jest on szerszy niż podany parametr szerokość. W czwartym przykładzie wydano polecenie wydrukowania pola [2] wyrównanego do prawej – do punktu 10,20. W piątym przykładzie mamy tekst obrócony o kąt 90 stopni w lewo.

W danych pola tekstowego wymagane są jedynie współrzędne oraz tekst do wydrukowania. Pozostałe parametry można pominąć – używamy ich jedynie wtedy gdy chcemy uzyskać wygląd inny niż domyślny. W definicji czcionki użytej w polu tekstowym również można pominąć część parametrów, np.

	 T=10,20|FAKTURA VAT|,16,BI

 oznacza żądanie użycia czcionki domyślnej o rozmiarze 16 pogrubionej i pochylonej

 Dozwolone oznaczenia stylu czcionki to 
	B - pogrubienie
	I - pochylenie
	U - podkreślenie
	S - przekreślenie

 Można je łączyć razem, np. BU, albo BIS

Dozwolone oznaczenia wyrównania tekstu to 
	L – do lewej
	R – do prawej
	C – na środek

W polu tekstowym można umieszczać nie tylko gotowe teksty, ale również pola danych, zmienne i wyrażenia tekstowe lub liczbowe. Przykłady takiego użycia pól tekstowych znajdziesz przy okazji omawiania tych elementów skryptów.

Pole danych
P<nr>=<współrzędne>,<wyrównanie lub szerokość>|<wartość_domyślna>|<czcionka>   np.

	P23=40,120|0,00|,,B

to pole zawierające dane dynamicznie ustalane przez program w momencie rozpoczęcia wydruku. Składnia parametrów identyczna jest ze zwykłym polem tekstowym. Tekst wpisany jako drugi parametr (po współrzędnych) to domyślna wartość pola w przypadku, gdy program nie poda żadnej (nawet pustej) wartości dla pola. Domyślną wartość można pozostawić pustą - w najprostszym przypadku, gdy nie określamy domyślnej wartości i używamy standardowej czcionki, składnia będzie np. następująca:

	P120=100,145

Ramka
R=<współrzędne_i_wymiary>|<grubość ramki>|<kolor>   np.

	R=10,10,200,280|2|RED

to ramka pusta wewnątrz – jeżeli użyto parametru TRANSPARENT, nie zasłania ona innych obiektów. Domyślna grubość ramki wynosi 1, kolor czarny. Tu również (jak i w następnych obiektach) można pominąć dalsze parametry, jeśli chcemy użyć wartości domyślnych (obowiązkowe są tu jedynie współrzędne i rozmiary).

Prostokąt wypełniony
B=<współrzędne_i_wymiary>|<grubość ramki>|<kolor_wypełnienia>   np.

	B=10,10,200,280|2|SILVER

to prostokąt wypełniony zadanym kolorem. Domyślnie jest to kolor czarny. Prostokąt nie ma obramowania – jeśli jest ono potrzebne, należy po jego wydrukowaniu wydrukować żądaną ramkę (patrz poprzednie polecenie).

Grafika
I=<współrzędne_i_rozmiary>|<nazwa_pliku_obrazka>    np.

	I=10,10,30,30|logo.bmp    lub
	I=40,40|tlo.jpg

to element graficzny znajdujący się w zadanym pliku. Zakładamy, że plik ten znajduje się w tym samym katalogu, co formularz wydruku. Dozwolone są następujące formaty pliku: BMP, JPG, WMF, ICO. Jeśli rozmiary obrazka nie zostaną jawnie podane, zostanie on wydrukowany w swoich naturalnych rozmiarach. Jeśli rozmiary będą podane, obrazek zostanie odpowiednio rozciągnięty lub skurczony.

Linia
L=<współrzędne,wymiary>|<grubość_linii>|<kolor>   np.

	L=10,10,200,10|2|RED

to linia zaczynająca się w punkcie o podanych współrzędnych. Wymiary są określane jako boki "teoretycznego" prostokąta, którego przekątną jest nasza linia. Domyślna grubość linii wynosi 1, kolor czarny. Aby uzyskać linię poziomą, należy podać wysokość równą 0, np.

	L=10,50,200,0

Analogicznie aby uzyskać linię pionową, należy podać szerokość równą 0, np.

	L=10,50,0,280|3|BLUE

Etykieta
LABEL <nazwa_etykiety>

Jest to definicja etykiety  używana np. przy instrukcji powtórzenia drukowania części formularza. Przykład użycia – patrz opis polecenia REPEAT.

Powtórzenie
REPEAT <od_etykiety,do_etykiety>,<przesunięcie_X,przesunięcie_Y,ilość> np.

	DX=120
	DY=105
	REPEAT przelew_start,przelew_end 

To rozkaz powtórzenia drukowania części formularza zawartej między podanymi etykietami zadaną ilość razy. W każdej iteracji aktualne przesunięcie DX i DY dostaje zwiększone o podane wartości <przesunięcie_x> i <przesunięcie_y>. Parametry te są jednak opcjonalne – w przypadku jednokrotnego powtórzenia nie ma potrzeby ich podawania (oraz podawania ilości powtórzeń). Po zakończeniu wykonywania polecenia przywracana jest wartość przesunięcia DX i DY sprzed wywołania polecenia. 

Przykład zastosowania : przelew bankowy czteroodcinkowy to w zasadzie powtórzony i przesunięty w różne miejsca ten sam odcinek (pomijając literki A,B,C,D). W świetle tych faktów można zbudować następujący formularz:

.
ogólne_definicje (linie podziału kartki, czcionki, literki ABCD itp.)

LABEL przelew_start
;tu definicja jednego odcinka przelewu
LABEL przelew_end

;odcinek B
DX=0
DY=105
REPEAT przelew_start,przelew_end

;odcinek C
DX=135
DY=0
REPEAT przelew_start,przelew_end

;odcinek D
DX=135
DY=105
REPEAT przelew_start,przelew_end

Dzięki tej technice można poważnie uprościć budowę wielu formularzy – tych wszystkich, na których występują powtarzające się sekcje różniące się jedynie położeniem na stronie. 

Inny przykład:

	LABEL linia_start
	L=0,10,210,10
	LABEL linia_end
	REPEAT linia_start,linia_end,10,0,9

skutkuje narysowaniem 10 linii (pierwotnej i dziewięciu powtórzonych) poziomych w odstępach pionowych 10 mm.

UWAGA! W celu uniknięcia zapętlenia i nieskończonej rekurencji nie jest dozwolone użycie polecenia REPEAT w sekcji formularza będącej już przedmiotem innego polecenia REPEAT.

UWAGA! W sekcji powtarzanej polecenia przesunięcia DX i DY są poleceniami względnymi – powodują one ustawienie punktu odniesienia względem dotychczas obowiązującego punktu odniesienia!!! Normalnie DX i DY zamienia poprzednią wartość, gdyż jest traktowane jako wartość bezwzględna przesunięcia względem początku kartki. W sekcjach powtarzanych należy zatem używać przesunięć DX i DY rozważnie. 

Bardziej zaawansowanym mechanizmem pozwalającym na wielokrotne wykorzystanie tego samego kodu są procedury – i powyższy przykład wygląda znacznie ciekawiej z użyciem procedur. Są jednak momenty, gdy pętla repeat jest niezastąpiona – było tak przy projektowaniu formularza przelewu ZUS, gdzie dzięki pętli repeat formularz zmniejszył i uprościł się dwukrotnie.

Dołączenie zewnętrznego pliku
INCLUDE <nazwa_pliku_poleceń>

W formularzu w dowolnym miejscu można wstawić zestaw poleceń znajdujących się fizycznie w innym pliku. Służy do tego procedura INCLUDE. Działa ona tak, jakby bezpośrednio do formularza wpisano polecenia znajdujące się w dołączanym pliku. Polecenie INCLUDE można zatem wykorzystać do wstawiania do formularzy powtarzających się elementów (jak logo firmy lub nagłówek wydruku). W zewnętrznym pliku (np. LOGO.ARK) definiujemy zestaw poleceń odpowiedzialnych za wydrukowanie logo firmy i w formularzach dołączamy ten plik poleceniem INCLUDE. 

Polecenia w dołączanym pliku warto zdefiniować nie jako polecenia bezwzględne ale jako procedury (patrz nast. punkt). Umożliwia to swobodne pozycjonowanie na stronie formularza zdefiniowanych w zewnętrznym pliku elementów.

Innym możliwym zastosowaniem polecenia INCLUDE są style – spełniające dokładnie tę samą funkcję co style w języku HTML. Wystarczy w zewnętrznym pliku  (np. STYLE.ARK) zdefiniować procedury ustawiające różne rodzaje czcionek (nagłówek, linia seryjna, stopka, logo itp.), do każdego  formularza dołączyć procedurą INCLUDE formularz stylów i ustawiać czcionki nie bezwzględnym poleceniem FONT ale wywołaniem właściwej procedury. Dzięki temu zmiana stylu (czcionki) we wszystkich nagłówkach wszystkich formularzy wymaga jedynie zmiany definicji właściwej procedury w pliku STYLE.ARK.

UWAGA! Z uwagi na możliwość zapętlenia i nieskończonej rekurencji zagnieżdżone (mające miejsce wewnątrz pliku właśnie włączanego do formularza) użycie polecenia INCLUDE jest zostanie zignorowane. 

Definicja procedury
W formularzach można definiować procedury. Są to bloki poleceń ujęte w sekcję PROCEDURE <nazwa> i ENDPROC, np.

PROCEDURE LogoFirmy
    I=0,0|image.bmp
    T=0,30|DELTA Informatyka-Oprogramowanie|Arial CE,12,B
ENDPROC 

Procedura może posłużyć do tego samego celu, co pętla REPEAT – czyli do powtarzania pewnej sekwencji poleceń, z reguły jest jednak prostsza i bardziej elegancka w użyciu.

Definicja procedury może znajdować się w dowolnym miejscu formularza (nawet za miejscem, w którym sama procedura została użyta) – formularz jest przygotowywany dopiero po zanalizowaniu wszystkich znajdujących się w nim definicji procedur, etykiet i poleceń REPEAT.

UWAGA! Definicja procedury może również znajdować się w zewnętrznym pliku (formularzu) dołączanym do formularza poleceniem INCLUDE. Nie ma ponadto sensu w definicji procedury definiować innej procedury (procedury zagnieżdżone). Definicja taka zostanie zignorowana. 

Wywołanie procedury
CALL <nazwa_procedury>,<przesunięcie_x>,<przesunięcie_y>

To wywołanie zdefiniowanej w dowolnym miejscu formularza (lub dołączonym poleceniem INCLUDE pliku) procedury o podanej nazwie. Jeśli podane zostaną parametry  <przesunięcie_x> i <przesunięcie_y>,  to  wszystkie współrzędne użyte w procedurze zostaną zwiększone (zmniejszone w przypadku wartości ujemnych) o podane wartości.

Po zakończeniu wykonywania procedury przywracana jest wartość przesunięcia DX i DY sprzed wywołania procedury. UWAGA! Wewnątrz procedury polecenia przesunięcia DX i DY są poleceniami względnymi – powodują one ustawienie punktu odniesienia względem dotychczas obowiązującego punktu odniesienia!!! Normalnie DX i DY zamienia poprzednią wartość, gdyż jest traktowane jako wartość bezwzględna przesunięcia względem początku kartki. W procedurach należy zatem używać przesunięć DX i DY rozważnie! 

Dozwolone jest wywoływanie procedury z wnętrza innej procedury. Na twórcy formularza spoczywa obowiązek pilnowania, aby uniknąć zapętlenia przez wzajemne wywołanie się dwóch procedur. Przy wywoływaniu procedury wewnątrz innej procedury (procedury głównej) należy też pamiętać o tym, że obowiązujące współrzędne są względne i zależą od parametrów wywołania procedury głównej.

Procedurę można zakończyć wcześniej niż w momencie wykonania jej ostatniej instrukcji wywołując w niej polecenie EXIT. Polecenie to należy stosować w połączeniu z instrukcją warunkową IF omówioną dalej oraz wyrażeniami tekstowymi lub arytmetycznymi. Tutaj podamy jedynie prosty przykład wyjaśniający sposób użycia tej specjalnej instrukcji.

	IF {EVAL CENA<0} EXIT

Przy użyciu wywołania procedury formularz przelewu z przykładu do procedury REPEAT mógłby mieć jeszcze bardziej elegancki wygląd:

.
ogólne_definicje (linie podziału kartki, czcionki, literki ABCD itp.)

PROCEDURE przelew_bankowy
tu definicja jednego odcinka przelewu
ENDPROC

;odcinek A
CALL przelew_bankowy,0,0

;odcinek B
CALL przelew_bankowy,0,105

;odcinek C
CALL przelew_bankowy,135,0

;odcinek D
CALL przelew_bankowy,135,105

Powtórzenie procedury
REPEATCALL <nazwa_procedury>,<przesunięcie_x>,<przesunięcie_y>,<ilość>

To powtórzenie wykonania procedury o podanej nazwie zadaną ilość razy. W każdym kroku iteracji aktualne przesunięcie DX i DY jest zwiększane o podane wartości <przesunięcie_x> i <przesunięcie_y>, zaś sama procedura jak zwykle uwzględnia to przesunięcie.

W parametrach jak zwykle możemy używać nie tylko wartości liczbowych, ale również zmiennych i wyrażeń arytmetycznych. Dzięki temu przy drukowaniu raportów wielostronicowych można korzystać z polecenia repeatcall, któremu jako parametr przekazujemy ilość rekordów w tabeli, której zawartość drukujemy. Przykłady – niżej, przy omawianiu korzystania z baz danych.

Komunikat tekstowy
MESSAGE <wyrażenie>
 
Polecenie to powoduje wyświetlenie komunikatu <wyrażenie> w momencie dojścia programu do analizy tej linii formularza. Może ono przydać się przy projektowaniu formularza do kontrolowania poprawności zmiennych i wyrażeń użytych w formularzu. Parametr <wyrażenie> może być zarówno zwykłym tekstem, jak i wyrażeniem tekstowym lub arytmetycznym, zawierającym zmienne, pola danych, obliczenia itp. W tym drugim przypadku wartość wyrażenia jest obliczana – zaś w oknie z komunikatem podane jest zarówno samo wyrażenie jak i jego aktualna wartość. Więcej o wyrażeniach w punkcie 5.

6. Obliczenia w formularzach
Wstęp.
Jedną z ciekawszych możliwości dostępnych w formularzach jest obliczanie wyrażeń. Zdarza się, że w formularzu chcemy umieścić tekst lub liczbę będącą wynikiem operacji matematycznych lub tekstowych na polach danych zawartych w formularzu. Więcej – wyniku tej operacji możemy znowu  chcieć użyć do kolejnych obliczeń. Można to oczywiście uzyskać na poziomie programu – wprowadzając dodatkowe pola wyliczane przez program i przekazywane (jako już gotowe wyliczone wartości) do generatora wydruków. Jest to jednak o tyle niewygodne, że jakakolwiek zmiana algorytmu wyliczania zmusza nas do rekompilacji programu. Lekarstwem na to są właśnie wyrażenia obliczane przez nasz generator wydruków.

Uwaga! Nie należy oczekiwać, że przy użyciu prostego języka skryptowego możliwe będzie uzyskanie obliczeń o bardzo dużej złożoności – takie obliczenia należy zrealizować na poziomie programu, choćby ze względu na możliwość debugowania kodu i szybkiego wyłapania ewentualnych pomyłek.

Wyrażenia typu tekstowego
Wyrażenie tekstowe w polu  tekstowym lub polu danych rozpoczynamy słowem kluczowym STR. Po nim (po spacji) wpisujemy argumenty wyrażenia składające się z danych: tekstów i odwołań do pól danych oraz z  operatorów. Ciągi tekstowe występujące w wyrażeniu ujmujemy w apostrofy. Numery pól danych używanych w wyrażeniu ujmujemy w nawiasy kwadratowe. Przykłady danych dozwolonych w wyrażeniach tekstowych:

‘ ‘
‘ zł’
 [120]
PAGE
Kwota
dbKlienci:Nazwisko
Dozwolone operatory to operator konkatenacji (łączenia) ciągów tekstowych oznaczany znakiem + (plus) oraz operator subtrakcji (wycięcia) ciągu tekstowego oznaczany znakiem – (minus). Działanie operatora + jest oczywiste – sprowadza się do utworzenia nowego ciągu tekstowego będącego połączeniem ciągów tekstowych będących argumentami wyrażenia. Działanie operatora subtrakcji polega na USUNIĘCIU z ciągu tekstowego po lewej stronie operatora drugiego ciągu tekstowego – jeśli ten w ogóle występuje w pierwszym ciągu. Dozwolone jest tworzenie wyrażeń składających się z wielu argumentów i operatorów. Uwaga! Dla wyrażeń tekstowych nie zaimplementowano (i raczej nie będzie takiej potrzeby) obsługi nawiasów określających kolejność działań. Wynika stąd, że działania będą wykonywane w naturalnej kolejności od lewej do prawej. Przykłady prawidłowych wyrażeń tekstowych:

STR [20] + ‘ zł’
STR [21] + ‘ ‘ + [22] + ‘ ‘ + [23]
STR ‘Data wydruku: ‘ + DATE

Wyrażenia typu liczbowego
To wyrażenia wyliczane na podstawie wartości liczbowej argumentów i dające w wyniku również wartość liczbową. Wyrażenie liczbowe rozpoczynamy od słowa kluczowego EVAL lub FORMAT, po nim zaś wpisujemy argumenty i operatory wyrażenia. Podobnie jak w wyrażeniach typu tekstowego możemy odwoływać się do pól danych, wpisując w wyrażeniu ich numery ujęte w nawiasy kwadratowe. Wynikiem obliczenia wyrażenia typu liczbowego będzie ciąg tekstowy – w przypadku wyrażenia FORMAT odpowiedni sformatowany.

Dozwolone są następujące operatory matematyczne: 

•	dodawanie: znak + (plus) 
•	odejmowanie: znak – (minus)
•	mnożenie: znak * (gwiazdka)
•	dzielenie: znak / lub \ (slash i backslash)
•	nawiasy okrągłe określające kolejność wykonywanych działań

Przykłady prawidłowych wyrażeń typu liczbowego:

EVAL [20] + [21] + [22]
EVAL ([5] + [6]) * 100
EVAL (([2]+[3]) * [4]) / [5]
EVAL dbFaktury:Netto + dbFaktury:VAT
FORMAT ([5] + [6]) * 100,###,###.##

Użycie w wyrażeniu słowa EVAL pozwala tylko na wykonanie obliczeń. Jeżeli jednak wynik ten ma być przedstawiony w określonej formie – sformatowany wg zadanej maski do określonej szerokości i z określoną precyzją dziesiętną,  lepiej użyć słowa kluczowego FORMAT.  

Zmienne predefiniowane
To specjalne wartości wyliczane na bieżąco w trakcie przygotowania raportu. Dostępne są następujące zmienne predefiniowane:

•	aktualna data:  DATE
•	aktualny czas: TIME
•	numer strony wydruku: PAGE
•	aktualny rekord w tabeli tekstowej: RECNO
•	ilość rekordów w tabeli tekstowej: RECORDCOUNT
•	ilość rekordów pozostała do zanalizowania w tabeli tekstowej: RECORDLEFT
•	ilość pól w rekordzie tabeli tekstowej: FIELDCOUNT

Tabele tekstowe to specjalny rodzaj danych przekazywanych przez program do formularza, pozwalający na korzystanie z nich podobnie jak ze zwykłych tabel danych Paradox czy DBF, jednak bez potrzeby używania sterowników BDE. Więcej o tej technice w następnych punktach.

Zmienne
Jak wspomniano we wstępie, może zachodzić potrzeba wykorzystania wyniku wyrażenia do obliczenia dalszych wyrażeń występujących w formularzu. Można to zrobić na dwa sposoby:

a)	poprzez utworzenie nowego pola danych, jeśli wynik wyrażenia ma być wydrukowany, a potem dopiero użyty do dalszych obliczeń.
b)	poprzez zdefiniowanie zmiennej zawierającej wartość wyliczoną wg podanego wyrażenia, używanej w dalszych obliczeniach

Sposób a) jest naturalny i oczywisty: w formularzu tworzymy linię zawierającą dyspozycję wydrukowania pola danych, gdzie jako wartość pola podajemy nasze wyrażenie. Pole zostanie wydrukowane, ale jego wartość zachowana tak, aby w następnych wyrażeniach można było odwołać się do tego pola. Przykłady:

P120=10,120|EVAL ([100] + [101] + [102]) * 0.10
P121=10,130|STR [P120] + ‘ zł’

Sposób b) jest o tyle ciekawszy, że zmienna wyliczona z wyrażenia może nie pojawić się nigdzie na naszym wydruku, ale mimo to być “aktywnym” członkiem wszystkich dalszych wyrażeń i mieć wpływ na ich  wyniki. Zmienną definiujemy poleceniem 

SET <nazwa_zmiennej>=<typ_wyrażenia> <wyrażenie>    np.

SET KwotaVAT=EVAL [20] * 0.22
SET SUMA15=EVAL [11] + [12] + [13] + [14]
SET SUMA_ZL=STR [25] + ‘ zł’
SET DATA=STR DATE

Wyrażenia w wyliczeniu wartości zmiennej to zwykłe wyrażenia tekstowe lub liczbowe. Nazwy zmiennych podlegają pewnym restrykcjom. Otóż:
a)	nazwa zmiennej może mieć praktycznie dowolną długość. W nazwie nie wolno używać spacji. Nie ma znaczenia, jakiej wielkości znaków używamy w definicji i odwołaniach do zmiennej – można zdefiniować zmienną wielkimi literami a odwoływać się do niej używając małych liter. Komu służą te uniksowe  dziwactwa z rozróżnianiem wielkości liter... Wyrazy współczucia dla programistów C i C++.
b)	nazwa zmiennej powinna była unikalna w ramach formularza (lub wszystkich elementów formularza, jeżeli zawiera on elementy dołączane poleceniem INCLUDE). Nie istnieje tu podział na zmienne lokalne i globalne – każda zmienna jest globalna i dostępna w każdej procedurze skryptu. 
c)	Ponowne zdefiniowane zmiennej o tej samej nazwie skutkuje tylko zmianą jej wartości na nowo określoną. Dzięki temu można jednej zmiennej używać do różnych celów.
d)	nazwa zmiennej nie może być liczbą. W przypadku zdefiniowania zmiennej o nazwie będącej liczbą analizator poleceń odwołania do niej będzie traktował jak zwykłe liczby. 

Zmiennej możemy używać naprzemiennie zarówno w wyrażeniach tekstowych jak i arytmetycznych. Jeśli przypadkiem użyjemy pola lub zmiennej z zawartością tekstową w wyrażeniu liczbowym, potraktowane będzie ono jako wartość zerowa.

W wyrażeniach odwołujemy się do zmiennej poprzez użycie jej nazwy. Nie jest dozwolone jest ujmowanie nazwy zmiennej w nawiasy kwadratowe (na podobieństwo pola danych). W przypadku napotkania takiej konstrukcji program najpierw wyliczy wartość zmiennej znajdującej się w nawiasach, a potem poszuka i zwróci wartość pola danych o wyliczonym numerze (bo kwadraty sugerują, że chodzi nam o pole danych). 

Przykłady użycia zmiennych:

T200=10,180|STR SUMA_ZL
SET NALEZNOSC=STR ’RAZEM do zapłaty: ‘ + SUMA_ZL

Aby zmienić wartość uprzednio zdefiniowanej zmiennej, należy użyć również polecenia SET. Nadaje ono nową wartość zmiennej – jeżeli taka zmienna nie istnieje, zostaje w tym momencie utworzona. W wartości można używać zarówno liczb i ciągów, jak i standardowych wyrażeń tekstowych lub liczbowych, np.

SET KWOTA=100.23
SET KWOTA=[100] + [101]
SET Numer=STR ’Faktura Vat nr ‘+[10] 

UWAGA! Bardzo ważną zaletą zmiennych jest to, że można używać ich również do określania numerów pól,  określania współrzędnych oraz wymiarów obiektów! Przykładowym zastosowaniem będzie obramowanie kilkunastu linii tekstu przekazanych przez program. Może się zdarzyć, że użytkownik wpisze ich mniej, a więc i obramowanie powinno być odpowiednio mniejsze – jego wysokość można uzależnić od tego, czy pola będą zawierały jakąś wartość:

SET WYSOKOSC=0
IF {[10]} SET WYSOKOSC=WYSOKOSC+1
IF {[11]} SET WYSOKOSC=WYSOKOSC+1
IF {[12]} SET WYSOKOSC=WYSOKOSC+1
IF {[13]} SET WYSOKOSC=WYSOKOSC+1
IF {[14]} SET WYSOKOSC=WYSOKOSC+1
R=10,100,120,WYSOKOSC * 10

Szczegóły na temat funkcjonowania instrukcji warunkowej IF znajdują się dalej, w punkcie 6.

Funkcje tekstowe i matematyczne
To dodatkowe instrumenty pozwalające na wykonywanie na zmiennych i polach danych działań niedostępnych przy użyciu standardowych operatorów. Są to np. operacje zaokrąglenia wartości liczbowej, zamiany małych liter na duże i odwrotnie, wyrównania tekstu spacjami  do określonej szerokości itp. W celu wywołania funkcji posługujemy się znanym już słowem kluczowym EVAL - po nim podajemy nazwę funkcji, nazwę pola lub zmiennej będącej jej argumentem oraz ewentualne parametry. Wobec tego aby np. wydrukować pole liczbowe zaokrąglone do 0.10, należy:

•	zdefiniować zmienną reprezentującą zaokrąglaną wartość
•	zaokrąglić tę zmienną
•	wstawić do formularza pole tekstowe z zaokrągloną już zmienną

Przykład:

SET Tax=EVAL ([100] + [101] + [102]) * 0.22
EVAL ROUND Tax,0.10
T=120,100|STR Tax

Oto wykaz dozwolonych funkcji:

•	ROUND <zmienna_lub_pole>,<precyzja>   : zaokrągla podaną zmienną lub pole z zadaną precyzją
•	INT <zmienna_lub_pole>   : oblicza wartość całkowitą liczby (obcinając część po przecinku)
•	FRAC <zmienna_lub_pole>   : oblicza wartość ułamkową liczby (obcinając część przed przecinkiem)
•	INC <zmienna_lub_pole>,<wartość> : zwiększa pole lub zmienną o zadaną wartość. Jeśli podana zostanie wartość ujemna, zmienna zostanie zmniejszona.
•	ODD <zmienna_lub_pole> : zwraca 1, jeśli podana liczba jest nieparzysta, 0 – gdy liczba jest parzysta. W przypadku podania liczby z częścią ułamkową pod uwagę brana jest tylko część całkowita liczby (ułamek nie jest zaokrąglany, ale odrzucany)
•	UPCASE <zmienna_lub_pole>   : zamienia wszystkie litery w ciągu na duże
•	LOCASE <zmienna_lub_pole>   : zamienia wszystkie litery w ciągu na małe
•	PAD <zmienna_lub_pole> ,<szerokość>,<znak>  : dopełnia ciąg z prawej strony podanym znakiem do żądanej szerokości. Jeśli nie podamy znaku wypełnienia, domyślnie będzie to spacja
•	LEFTPAD <zmienna_lub_pole> ,<szerokość>,<znak>  : dopełnia ciąg z lewej strony podanym znakiem do żądanej szerokości
•	TRIM <zmienna_lub_pole>: obcina wszystkie spacje na początku i na końcu ciągu
•	SAY <zmienna_lub_pole> zamienia podane pole z wartości liczbowej w jej reprezentację słowną
•	FORMAT <zmienna_lub_pole>,<maska>: formatuje zadaną wartość liczbową wg zadanej maski. W masce można określić precyzję (ilość miejsc po przecinku) oraz ilość znaków. 

7. Odwołania do obiektów
Umieszczając w formularzach polecenia wydrukowania obiektów takich jak teksty, ramki, pola danych i inne możesz łatwo odwołać się do parametrów innych wcześniej wydrukowanych obiektów. Przykładowo na stronie mogą znaleźć się dwie ramki o tej samej szerokości, druga o 10 mm niżej od pierwszej. Warto w poleceniu drukowania drugiej ramki odwołać się do szerokości pierwszej ramki – jeżeli zmienimy szerokość pierwszej ramki, druga zostanie zmieniona automatycznie! Jak to zrobić?

Po pierwsze w definicji pierwszego obiektu musisz określić jego unikalną nazwę, za pośrednictwem której będziesz odwoływał się do właściwości obiektu. Nazwa musi być unikalna w ramach całego formularza i dołączanych do niego plików. Nazwa obiektu nie może być też taka sama jak nazwa którejkolwiek ze zmiennych użytych w formularzu! Nieprzestrzeganie tej zasady skutkuje przysłanianiem jednych zmiennych przez drugie i nieprzewidzianymi efektami na wydruku!!!

Aby określić nazwę obiektu, w jego definicji umieszczamy słowo NAME a po nim nazwę. Wielkość liter nie ma tu znaczenia. W naszym przykładzie byłoby to:

R NAME Ramka1=20,20,130,70

Polecenie drukowania drugiej ramki (spełniającej powyższe wymagania) mogłoby wyglądać następująco:

R=20,100,130,70

ale nie jest to najlepsze rozwiązanie – jeśli kiedykolwiek zechcesz przesunąć w pionie lub zmienić wysokość pierwszej ramki, będziesz musiał pamiętać o odpowiedniej zmianie parametrów drugiej ramki! Korzystając z możliwości odwołania do obiektów zdefiniujmy drugą ramkę w następujący sposób:

R=Ramka1.X, Ramka1.Y+Ramka1.H+10, Ramka1.W, 50

W efekcie uzyskamy ramkę, która zawsze będzie miała tę samą współrzędną X oraz szerokość co ramka pierwsza, i będzie położona o 10 mm od niej niżej – niezależnie od tego, jak będziemy zmieniać współrzędne i wymiary pierwszej ramki!!! Prawda, że proste?

Do właściwości obiektu odwołujemy się zatem podając nazwę obiektu, kropkę i nazwę właściwości. Dozwolone są odwołania do następujących właściwości obiektów:

X to współrzędna pozioma obiektu
Y to współrzędna pionowa obiektu
W to szerokość obiektu
H to wysokość obiektu
Text to tekst związany z obiektem

Odwołując się do właściwości Text obiektu należy pamiętać, że w sytuacji gdy obiekt ten zawiera wyrażenie tekstowe (a nie zwykły tekst), wartość tego wyrażenia będzie obliczona dopiero w momencie drukowania tego obiektu! Nie ma więc sensu wcześniejsze odwoływanie się do tej wartości – należy mieć na uwadze w jakiej kolejności obiekty będą umieszczane na stronie, aby w odpowiednim momencie odwoływać się do ich właściwości Text.

Używając właściwości TEXT możemy odwoływać się również do poszczególnych znaków pola tekstowego lub zmiennej. Wystarczy użyć właściwości Text w nieco bardziej rozbudowany sposób, np.

SET NUMER=STR [23]
T=10,10|STR NUMER.TEXT[1]
T=10,15|STR NUMER.TEXT[2]
T=10,20|STR NUMER.TEXT[3]

to wydrukowanie kolejnych trzech liter pola danych nr 23 w kolumnie jeden pod drugim. Praktyczne zastosowanie dostępu do poszczególnych liter pól tekstowych można spotkać przy drukowaniu przelewów ZUS, gdzie szerokość kratki pola nijak się ma do rozmiarów standardowych czcionek Windows – i z tego powodu konieczne jest drukowanie pól znak po znaku. Aby uniknąć w tym wypadku mozolnego drukowania znak po znaku warto skorzystać ze zmiennych i procedur powtarzalnych (RepeatCall).

Odwołania do właściwości obiektu mogą mieć miejsce wszędzie – są one używane tak samo jak zmienne. Możesz więc używać ich do ustalenia współrzędnych lub wymiarów innych obiektów, używać ich w obliczeniach matematycznych i w tworzeniu ciągów tekstowych, w definicjach i obliczeniach zmiennych, w instrukcjach warunkowych i w parametrach procedur. Daje to niezwykłą swobodę w tworzeniu zależności między obiektami. Wykorzystując w inteligentny sposób odwołania do obiektów zaoszczędzisz w przyszłości ogromną ilość czasu, jeśli będziesz zmieniał wygląd swoich formularzy!

8. Instrukcje warunkowe
Instrukcje warunkowe to bardzo przydatne narzędzie umożliwiające kształtowanie wydruków “w locie” – ich wygląd może być różny w zależności od spełnienia określonych warunków. Aby wykonać dowolne polecenie warunkowo, należy poprzedzić je instrukcją sprawdzenia warunku:

IF <warunek> <instrukcje_do_wykonania>

Pole <warunek> to ogólnie dwa wyrażenia połączone operatorem relacji. Przy konstruowaniu wyrażenia używamy standardowych poleceń i sformułowań, omówionych w poprzednich punktach. Dozwolone są operatory relacji:

•	równy : znak = 
•	różny : znak <>
•	mniejszy: znak  < 
•	większy : znak > 
•	mniejszy lub równy : znak  <= 
•	większy lub równy: znak >= 
•	zawiera : znak $. Operator ten nie ma sensu dla wyrażeń typu liczbowego!

Cały warunek musi być ujęty w nawiasy klamrowe. Przykładowe warunki:

IF {STR [11]<>’’} T=10,10|STR ‘Nazwisko: ‘ + [11]

to polecenie wydrukowania pola nr 11 poprzedzonej tekstem ‘Nazwisko:’, ale tylko wtedy, gdy pole to nie jest puste.

IF {STR Typ=’1’} T=10,100|X
IF {STR Typ=’2’} T=10,105|X

to polecenie wydrukowania znaku X  w różnych miejscach w zależności od wartości zmiennej TYP. Pozostałe przykłady powinny już być oczywiste:

IF {EVAL Total>0} SET Razem=STR Total
IF (EVAL Total<=0) SET Razem=’0,00’

SET Podatek=EVAL ([10]+[11]+[12])*0.2
IF (EVAL Podatek<=0) SET Podatek=EVAL 0

W niektórych warunkach dozwolone jest stosowanie pewnych uproszczeń. Po pierwsze – nie ma potrzeby zaznaczania, że badane mają być ciągi tekstowe (użycie deklaracji STR). Jeśli w wyrażeniach warunku nie użyjemy deklaracji EVAL, zostaną one potraktowane jako ciągi tekstowe. Po drugie – uproszczoną formę może przybrać sprawdzenie, czy pole jest puste (jeden z częściej sprawdzanych warunków). W tej sytuacji powyższe przykłady przybrałyby formę:

IF {[11]}
IF {Typ=’1’}

Obie formy są dozwolone i jest kwestią wygody, którą z nich zdecydujesz się użyć. Podkreślamy, że nadal konieczne jest użycie deklaracji EVAL, jeśli chcemy badać wartości liczbowe pól i zmiennych. Ma to kluczowe znaczenie przy operatorach > oraz <  - wartość liczbowa ciągu ‘11’ jest większa niż wartość ciągu ‘2’, natomiast wartość tekstowa ‘11’ jest mniejsza (!) od wartości tekstowej ciągu ‘2’. 

9. Obsługa tabel tekstowych (raporty wielostronicowe)
Wprowadzenie
Nasz analizator skryptów potrafi drukować nie tylko proste wydruku typu “formularz” zawierające zawsze stałą i określoną liczbę pól i stron, ale również i raporty wielostronicowe. Raport taki może zawierać np. wykaz towarów znajdujących się w magazynie. Określona tu jest raczej ilość i wygląd pól w jednej linii niż ilość wydrukowanych rekordów i stron raportu. Z tego powodu w raporcie definiujemy tzw. linię seryjną (linię powtarzalną), która będzie powielona odpowiednią ilość razy – stosownie do ilości drukowanych rekordów. Uwaga! W raporcie może znaleźć się więcej linii seryjnych – np. na ostatniej stronie raportu sprzedaży niezapłaconej możemy zdefiniować kolejną linię seryjną zawierającą listę adresów i telefonów naszych dłużników!

Dane do wydrukowania wielostronicowego raportu mogą pochodzić ze standardowej  tabeli danych (z użyciem sterowników BDE) – o czym więcej w następnym punkcie, jak również mogą być przekazane do formularza w postaci tzw. tabeli tekstowej, gdzie nie musimy korzystać z BDE. W większych aplikacjach zalecamy korzystanie z BDE, ale przy małych programach narzędziowych, w których zależy nam na jak najmniejszym rozmiarze pliku wynikowego,  może to być wielką zaletą!

Do wydrukowania raportu wielostronicowego użyte zostaną standardowe mechanizmy znane już z raportów typu “formularz”, wzbogacone o dodatkowe funkcje dostępu do kolejnych rekordów tabeli tekstowej i ich pól. W zasadzie możliwe jest skonstruowanie poprawnie drukującego się raportu wyłącznie z użyciem zwykłych poleceń – ale jego budowa będzie mało przejrzysta – konieczne jest bowiem dokonywanie obliczeń numerów pól drukowanych w kolejnych liniach oraz niezbyt proste generowanie stopek i nagłówków. Nowe elementy języka opisu raportu tutaj opisane znakomicie ułatwiają stworzenie raportu wielostronicowego.

Przekazywanie danych do raportu.
Poszczególne rekordy do wydrukowania w raporcie przekazujemy w pliku tekstowym. Dla każdej tabeli zawartej w pliku tekstowym tworzymy osobną sekcję oznaczoną unikalną nazwą tabeli. W nagłówku sekcji podajemy nazwę tabeli, ilość pól w rekordzie oraz numer pierwszego pola naszego rekordu – następne pola będą miały kolejne numery. Następnie umieszczamy linie zawierające poszczególne pola rekordów. Pola powinny być oddzielone separatorem w postaci ciągu znaków </>

Przykład:
TABLE TOWARY,6,100
czekolada Milka Yoghurt</>CG001</>2.20</>2.45</>2.90</>300.00
wafel Grzesiek</>WF001</>1.20</>1.45</>1.90</>120.00
wafel Prince Polo Max</>WF002</>1.40</>1.80</>2.10</>30.00
wafel Prince Polo Mini</>WF003</>0.90</>1.10</>1.19</>1200.00
wafel Prince Polo Standard</>WF004</>1.20</>1.40</>1.60</>10.00
wafel Goplana orzechowy</>WF005</>2.20</>2.70</>2.90</>60.00
ENDTABLE

Mogłoby się wydawać, że ilość pól podana w nagłówku tabeli jest parametrem nadmiarowym – jednakże jest ona niezbędna w sytuacji, gdy rekordy będą niekompletne – tj. będą zawierały raz dwa, raz trzy a innym razem wszystkie pola. Gdyby ilość pól była określana na podstawie bieżącego rekordu, okazałoby się że część pól drukuje się w raporcie z wartościami z poprzedniego rekordu – bo bieżący rekord mający mniej pól nie zmienił ich wartości ani nie wyzerował! Ilość pól w tabeli dostępna jest w naszym formularzu jako zmienna predefiniowana FIELDCOUNT - na wypadek gdyby zaszła kiedykolwiek potrzeba jej wydrukowania lub użycia w instrukcjach warunkowych.

W formularzu w procedurze opisującej naszą linię seryjną będziemy się odwoływać do pól poprzez numery 100 (nazwa towaru), 101 (indeks), 102 (cena zakupu) itd. Należy uważać, aby użyte numery nie przesłoniły ewentualnych numerów pól danych używanych poza linią seryjną! 

Definicja i wywołanie linii seryjnej
Linię seryjną najwygodniej będzie zdefiniować w procedurze. W procedurze używamy współrzędnych względnych – jeżeli zatem wywołamy ją poleceniem REPEATCALL (wielokrotne wywołanie tej samej procedury), spowoduje to automatyczne dodanie odpowiedniego przesunięcia Y (i ewentualnie X) dla każdego wywołania linii seryjnej – a więc drukowanie kolejnych linii coraz niżej (lub dalej). Ilość powtórzeń linii seryjnej na stronę  - ostatni parametr polecenia REPEATCALL - należy dobrać stosownie do ilości miejsca na stronie wydruku. Poza standardowymi poleceniami wyświetlającymi poszczególne pola w odpowiednich miejscach należy w procedurze umieścić polecenie wczytania kolejnego rekordu. W procedurze można korzystać ze specjalnej automatycznie zdefiniowanej zmiennej RecNo, która zawiera numer aktualnego rekordu. Dla powyższego przykładu można zdefiniować następujący formularz:

;formularz testowy – wydruk linii seryjnej
TRANSPARENT
FONT=Arial CE,10
MEASURE=MM

PAGE 0,0

PROCEDURE LiniaTowarowa
  ;załadowanie do pól 100, 101 etc. pól kolejnego rekordu
  NEXTRECORD Towary
  ;wydrukowanie rekordu
  T=11,2|STR RecNo
  T=17,2|STR [100]
  T=55,2|STR [101]
  T=70,2|STR [102]
  T=85,2|STR [103]
ENDPROC

DY=20
REPEATCALL LiniaTowarowa,0,5,40
IF {EVAL RecNo<RecordCount} REPEATPAGE 1

END

Zdefiniowana procedura służy do wydrukowania jednej linii zawierającej dane o towarze. Jako pierwsza czynność w procedurze wykonywane jest wczytanie kolejnego rekordu z tabeli rekordów. Odpowiedzialne za to jest polecenie

NEXTRECORD <nazwa_tabeli_danych>

Przy pierwszym wywołaniu wczytuje ono z pliku danych rekordy tabeli o zadanej nazwie. Następnie zmienia numer kolejnego rekordu o 1 i wpisuje do właściwych dla danej tabeli pól (patrz p.2) wartości wzięte z tego rekordu. Numer bieżącego rekordu dostępny jest w zmiennej predefiniowanej RECNO. Po tej operacji możemy już odwoływać się do tych pól – drukując je w dowolny pożądany sposób. Procedura NEXTRECORD bada przy okazji, czy nie osiągnięto już ostatniego rekordu w tabeli – jeśli tak, kończy wykonywanie procedury. Jak łatwo zgadnąć, dostępne jest również polecenie

PREVRECORD <nazwa_tabeli_danych>

które cofa się do poprzedniego rekordu i podaje jego wartość. Cofnięcie może się przydać np. wtedy, gdy jeszcze przed wydrukowaniem linii seryjnej potrzebna jest nam informacja o ilości pól i rekordów w tabeli. Wystarczy wywołać wtedy procedurę NEXTRECORD, aby tabela została wczytana i ustawione zostały potrzebne nam zmienne, po czym wywołać PREVRECORD, aby wrócić do początku tabeli (przed pierwszy rekord). Najlepiej jest taka operację wykonać jeszcze przed zainicjowaniem pierwszej strony wydruku (przed pierwszym poleceniem PAGE w formularzu) – wstawienie operacji PREVRECORD np. w definicji nagłówka (sekcja HEADER) skutkuje wywołaniem jej dla każdej drukowanej strony – a więc możemy uzyskać niepożądany efekt w postaci cofnięcia numeru aktualnego rekordu!!!

Po zakończeniu drukowania linii seryjnej należy zbadać, czy pozostały do wydrukowania jeszcze jakieś rekordy – jeśli tak jest, należy powtórzyć wydruk tej strony formularza dla dalszych rekordów. W powyższym przykładzie użyta do tego celu została konstrukcja: 

IF {EVAL RecNo<RecordCount} REPEATPAGE 1

Konstrukcja ta sprawdza, czy aktualny rekord jest ostatnim rekordem. Jeżeli tak nie jest, analiza pierwszej strony skryptu zostanie powtórzona – dla następnych rekordów czekających na wydrukowanie. Dopiero po dojściu do ostatniego rekordu analiza formularza zostanie zakończona (lub zostaną zanalizowane dalsze strony, jeśli zostały zdefiniowane). W konstrukcji tej pojawia się znowu omówiona wcześniej zmienna RecNo oraz kolejna automatycznie tworzona zmienna: RecordCount zwracająca ilość rekordów w linii seryjnej oraz omówione wcześniej polecenie REPEATPAGE, służące do powtórzenia analizy bieżącej strony od początku – tutaj znajdujące bardziej sensowne zastosowanie niż drukowanie strony w kilku egzemplarzach. 

Do sprawdzenia ile rekordów pozostało jeszcze do wydrukowania służy predefiniowana zmienna RecordLeft. Można jej użyć np. w celu dynamicznego dostosowania wysokości tabelki do ilości rekordów na stronie. Na pierwszej i dalszych stronach wydruku tabelka będzie miała określoną maksymalną wysokość a na ostatniej stronie mniejszą – właściwą dla pozostałej ilości rekordów. Przykładowy kod:

SET ItemH = 5
SET MaxOnPage = 30
............
PROCEDURE Tabelka
  SET TableH = EVAL MaxOnPage * ItemH
  IF {EVAL RecordLeft<MaxOnPage} SET TableH = EVAL RecordLeft * ItemH
  R=10,10,TableH,120
ENDPROC

UWAGA! Funkcji RepeatPage nie ma sensu wywoływać z wnętrza procedury lub pętli repeat. Jej wywołanie zostanie wówczas pominięte.
Zakończenie
W omówiony wyżej sposób uzyskujemy możliwość łatwego i szybkiego generowania raportów wielostronicowych. W połączeniu z omówioną wcześniej możliwością definiowania nagłówek i stopek oraz wykonywania obliczeń arytmetycznych (jak obliczanie sum pól) daje to nam niemal nieograniczone możliwości! W powyższym przykładzie można np. w procedurze drukującej linię seryjną wstawić polecenie wyliczania wartości towaru i jej sumowania, a otrzymaną wartość łączną drukować w stopce formularza. Dysponując tak wszechstronnym narzędziem inteligentny programista będzie w stanie wykorzystać nasz analizator skryptów do generowania dowolnych dających się wyobrazić wydruków! 

10. Dostęp do baz danych BDE.
Wstęp
Raporty projektowane z użyciem naszego języka skryptowego mogą korzystać z baz danych udostępnianych przez BDE - standardowy mechanizm obsługi baz danych dla programów napisanych w kompilatorach Borlanda. Dla uproszczenia sobie pracy, a jednocześnie udostępnienia programiście jak najsilniejszego instrumentarium zdecydowaliśmy się na udostępnienie w formularzach standardowych obiektów TDataset oraz zapytań SQL. Korzystamy z nich w sposób podobny do mechanizmów występujących w programach DELPHI czy BC++. Dzięki zapytaniom możliwe jest uzyskanie dostępu do dowolnych baz danych (zarówno przez ścieżkę bezwzględną jak i mechanizm aliasów), uzyskiwanie dostępu do tabel łączonych (polecenie JOIN), wyszukiwanie rekordów (poleceniem WHERE) – słowem wszystko to, co udostępnia składnia języka LocalSQL. Dzięki możliwości wykorzystania tabel przygotowanych przez aplikację w formularzu mamy natomiast natychmiastowy dostęp do danych, bez żadnych specjalnych przygotowań i zapytań.

Techniki dostępu do baz danych w formularzach
W formularzach można wykorzystać dwa rodzaje baz danych:

1)	tabele lub zapytania (czyli obiekty TDataSet lub potomne) otwarte, przygotowane i przekazane do formularza bezpośrednio przez aplikację
2)	tabele przygotowane do drukowania bezpośrednio przez formularz wydruku z wykorzystaniem zapytania SQL

W tym pierwszym przypadku programista tworzący aplikację udostępnia do wykorzystania w danym formularzu listę tabel, z których w formularzu można skorzystać. Więcej szczegółów w rozdziale Informacje dla programistów przy okazji omawiania metody AddTable.

W drugim przypadku tabela jest tworzona za pomocą poleceń otwarcia bazy danych zapisanych bezpośrednio w formularzu wydruku. Aplikacja wywołująca określony wydruk nie musi w ogóle zajmować się przygotowaniem tabel – zostaną one otwarte i ewentualnie przefiltrowane przy pomocy poleceń formularza. W celu uzyskania dostępu do bazy danych należy zdefiniować zapytanie (procedurę zawierającą w sobie treść zapytania SQL), a następnie w żądanym miejscu to zapytanie wywołać. Definicja zapytania SQL wygląda następująco:

SQL <nazwa_zapytania> TABLE <nazwa tabeli>
 .. tu treść zapytania
ENDPROC
np.
SQL WyszukajAdresyKlientow TABLE Klienci
  ;otwórz tabelę adresów posortowaną wg miasta
  select * from “:DELTA:ADRESY.DB” ORDER BY MIASTO
ENDPROC

Parametr TABLE <nazwa tabeli> służy do określenia nazwy tabeli rekordów powstałej w wyniku wykonania zdefiniowanego zapytania. Możliwe jest więc zdefiniowanie kilku alternatywnych zapytań do tej samej bazy (np. uwzględniających różne warunki), które w efekcie dadzą nam tabelę o tej samej nazwie. Dzięki temu przy drukowaniu tej tabeli możemy wykorzystać jedną wspólną procedurę odwołującą się do tej tabeli. Gdyby każde z naszych alternatywnych zapytań generowało osobną tabelę, musielibyśmy utworzyć osobne procedury do drukowania każdej z nich! Praktyczny przykład dalej, przy omawianiu zapytań sparametryzowanych.

W powyższym przykładzie otwieramy bazę danych ADRESY.DB dostępną pod aliasem DELTA, udostępniając wszystkie jej pola (znak *) i porządkując wg pola MIASTO. Uwaga! W odróżnieniu od standardowego SQL w naszych zapytaniach można umieszczać komentarze – jak zwykle rozpoczynając linię znakiem średnika. Tabela wynikowa będzie potem dostępna pod nazwą Klienci, zatem odwołując się do jej pól i metod będziemy używać tej właśnie nazwy.

Teraz należy wywołać nasze zapytanie SQL. Najlepiej jest to zrobić jeszcze przed rozpoczęciem pierwszej strony – gwarantuje to bezwarunkowe wykonanie zapytania. Zapytanie SQL wywołujemy poleceniem

PREPARESQL <nazwa_zapytania>     np.
PREPARESQL WyszukajAdresyKlientow

Zwracamy uwagę, że zapytanie wywołujemy poprzez jego nazwę, a nie nazwę tabeli powstałej w wyniku jego wykonania! Wskutek wykonania zapytania tworzona jest tabela o nazwie podanej w definicji zapytania parametrem TABLE i odtąd możemy się do niej odwoływać, pobierając wartości pól rekordów czy też poruszając się po rekordach.

Dostęp do pól tabeli
Od momentu uzyskania dostępu do tabeli  danych możemy w formularzu używać nowego rodzaju zmiennych – czyli pól tabeli. Pole tabeli określane jest przez jej nazwę oraz (po dwukropku) nazwę pola. Dwukropek (nie kropka!), jest tu koniecznym separatorem pomiędzy nazwą tabeli a nazwą pola. Niestety – nie można tu używać kropki, gdyż program potraktuje taki identyfikator jak odwołanie do podanej właściwości obiektu (np. pola tekstowego) o tej nazwie. Nasz język skryptów jest językiem bez kontroli typów zmiennych, a więc określenie typu zmiennej realizowane jest przez takie właśnie specyficzne konstrukcje językowe. Przykład odwołań do pól tabeli:

PROCEDURE PrintAdres
 T=10,10|STR dbKlienci:NIP
 T=10,14|STR dbKlienci:Nazwa
ENDPROC
Operacje na tabeli
Poza dostępem do pól tabeli możliwe jest też wywoływanie funkcji i metod na rzecz tabeli. Mogą one posłużyć do uzyskania informacji na temat tabeli (jak ilość rekordów w niej zawartych) oraz do wykonania operacji (np. przejście do następnego rekordu). 

Do wywołania metod operujących na tabeli używamy zwykłego polecenia CALL wywołującego zadaną metodę:

CALL <nazwa_tabeli>:<funkcja>  np.
CALL Klienci:Next

Dostępne metody to:

•	FIRST – przesuwa się do pierwszego rekordu, zwraca 0 gdy operacja powiodła się
•	LAST – przesuwa się do ostatniego rekordu (j.w.)
•	PRIOR – przesuwa się do poprzedniego rekordu (j.w.)
•	NEXT – przesuwa się do następnego rekordu (j.w.) 

Poza wykonywaniem metod możliwe jest uzyskanie informacji na temat tabeli, jak ilość rekordów czy numer aktualnego rekordu. Funkcje zwracające te informacje możemy umieszczać we wszystkich wyrażeniach arytmetycznych, tekstowych oraz warunkach logicznych występujących w formularzu – używamy ich podobnie jak zmiennych czy pól danych. W celu użycia funkcji zwracającej informację o tabeli podajemy w wyrażeniu nazwę tabeli a po dwukropku nazwę funkcji. Dostępne funkcje to:

•	EOF – zwraca wartość 1, gdy osiągnięto koniec tabeli, w przeciwnym razie 0
•	BOF – zwraca wartość 1, gdy osiągnięto początek tabeli, w przeciwnym razie 0
•	RECNO – zwraca numer bieżącego rekordu (pierwszy rekord ma numer 0)
•	COUNT – zwraca ilość rekordów w tabeli
•	LEFT – zwraca ilość rekordów pozostałych do końca tabeli (począwszy od następnego za bieżącym)

Wszystkie powyższe funkcje zwracają wartość –1, gdy operacja przez nie wykonywana zakończy się błędem. 

Używając powyższego zestawu funkcji i metod można zrealizować praktycznie wszystkie cele spotykane przy raportach, a więc: dostęp do kolejnych rekordów tabeli, możliwość poruszania się po tabeli, kontrolę nad pozycją w tabeli, co pozwala na ustalenie ilości stron raportu oraz ilości linii na stronę (dynamiczne ustawianie rozmiarów tabelek na dane itp.). Poniżej – przykład prostego formularza drukującego kolejne rekordy ze wskazanej tabeli, generującego nową stronę dla każdego kolejnego rekordu:

NAME=Test SQL
TRANSPARENT
FONT=Arial CE,10
MEASURE=MM

SQL SzukajKlientow TABLE Klienci
 select * from ":DELTA:adresy.db" order by MIASTO 
ENDPROC

PROCEDURE PrintAdres
 if {EVAL Klienci:EOF=1} EXIT
 T=10,14|STR Klienci:Nazwa1
 T=10,18|STR Klienci:Kod
 T=10,22|STR Klienci:Miasto
 T=10,26|STR Klienci:Ulica
ENDPROC

; otwórz tabelę adresów
PREPARESQL SzukajKlientow

;i drukuj
PAGE 0,0

;drukuj adres
CALL PrintAdres
;do następnego rekordu
CALL Klienci:Next
;powtórz stronę jeśli nie koniec
if {EVAL Klienci:EOF=0} RepeatPage 1

END
Zapytania warunkowe
Nieraz zachodzi konieczność uwzględnienia w drukowanym raporcie tylko niektórych rekordów bazy danych – spełniających określone przez nas warunki. Jak wiadomo, w zapytaniach SQL dozwolone jest korzystanie z klauzuli WHERE, gdzie można podać warunek jaki muszą spełniać rekordy przez nas wyszukiwane. Najprościej jest wpisać warunek bezpośrednio do zapytania, np. 

SQL SzukajKlientow TABLE dbAdresy
  ;otwórz tabelę adresów posortowaną wg miasta, adresy z Gdyni
  select * from “:DELTA:ADRESY.DB” WHERE MIASTO=”Gdynia” ORDER BY MIASTO
ENDPROC

Niestety w sytuacji, gdy użytkownik programu zechce wydrukować kontrahentów z Gdańska, będzie musiał osobiście modyfikować formularz wydruku, z czego raczej nie będzie zadowolony. Wygodniej byłoby przekazywać do formularza pewne wartości i użyć ich do zapytania sparametryzowanego. W standardzie LocalSQL możliwe jest używanie parametrów w zapytaniach – i tego też mechanizmu użyjemy w naszych zapytaniach. 

Zapytania sparametryzowane
Z reguły raport projektowany przez nas będzie zawierał dane spełniające określony przez użytkownika warunek. Kwestię przygotowania tabeli zawierającej tylko rekordy spełniające ten warunek można przerzucić na program – czyli umieścić w nim instrukcje przygotowujące tymczasową tabelę wywoływaną w naszym raporcie a po jego wydrukowaniu usuwaną. Podejście to jest o tyle niekorzystne, że w razie zażądania przez klienta zmiany algorytmu weryfikowania czy rekord ma być drukowany czy też nie, konieczne jest modyfikowanie programu (no i potem jego przeinstalowanie u – dajmy na to – trzystu użytkowników). Znacznie wygodniej byłoby umieścić całą logikę bezpośrednio w formularzu naszego raportu. Wiąże się to jednak z koniecznością sparametryzowania zapytań zwracających w wyniku rekordy spełniające określone warunki, czyli możliwość tworzenia zapytań, w których warunki nie zawierają wartości bezwzględnych, ale parametry (zmienne), których wartość jest ustalana dopiero w momencie wykonywania zapytania na podstawie danych przekazanych do formularza przez program. Przykład zapytania zawierającego parametry:

SQL SzukajKlientow TABLE dbAdresy
 Select * from “:DELTA:ADRESY.DB” WHERE (KOD>=:P1) AND (KOD<=:P2) ORDER BY KOD
ENDPROC

Nazwy parametrów użytych w zapytaniu mogą być dowolne – byle zaczynały się od dwukropka, jak wymaga tego standard LocalSQL. 

Aby wykonać zapytanie sparametryzowane, należy wywołać zapytanie SQL poleceniem PREPARESQL o nieco rozszerzonej budowie:

PREPARESQL <nazwa_zapytania>,<parametr1>,<parametr2>,......,<parametr n>      np.
PREPARESQL SzukajKlientow,[22],[23]

W powyższym przykładzie parametrami zapytania są dwa pola o numerze 22 i 23 przekazane do formularza przez program. To program inicjuje ich wartość (np. tekstami wpisanymi przez użytkownika w oknie dialogowym) – zaś nasze zapytanie ma te wartości wstawić w miejsce parametrów.

Parametrem przekazanym do zapytania może być:

•	Pole danych o określonym numerze, którego wartość ustawił program wywołujący drukowanie naszego formularza, np. [10] albo [15]
•	Zmienna zdefiniowana wcześniej w formularzu – a wartość tej zmiennej ta może być wynikiem operacji na różnych polach danych i wartościach, np.
SET Total=EVAL [31] + [32] + [33]
PREPARESQL Obroty,Total
•	Pole innej – otwartej wcześniej - tabeli, np.  PREPARESQL FakturyKlienta, dbKlienci:KlientNr

Liczba parametrów przekazanych do zapytania może być dowolna – do projektanta formularza należy zadanie dopilnowanie, by nie była mniejsza niż liczba parametrów użytych w zapytaniu. Przypisanie wartości parametrom następuje wg kolejności ich wystąpienia. Zatem pierwszy parametr, który wystąpił w zapytaniu otrzyma wartość pierwszej zmiennej podanej w wywołaniu zapytania, drugi parametr – wartość drugiej zmiennej i tak dalej. Przypisanie jest wykonywane wyłącznie na podstawie numeru porządkowego, a nie na podstawie nazwy. Narzuca to konieczność zachowania ostrożności, ale pozwala na maksymalne uproszczenie składni procedury PREPARESQL.

Bardziej inteligentnego rozwiązania wymagać będzie formularz uniwersalny, pozwalający na wydrukowanie zarówno tabeli filtrowanej wg warunku jak i nie filtrowanej, zawierającej wszystkie rekordy. Definiujemy w tym wypadku dwa zapytania zwracające w wyniku tabelę o tej samej nazwie, po czym jedno (i tylko jedno) z nich wywołujemy warunkowo, jak w poniższym przykładzie:

NAME=Koperty
TRANSPARENT
FONT=Arial CE,10
MEASURE=MM

SQL SzukajWszystkich TABLE dbAdresy
 Select * from “:DELTA:ADRESY.DB” ORDER BY KOD
ENDPROC

SQL SzukajPoKodzie TABLE dbAdresy
 Select * from “:DELTA:ADRESY.DB” WHERE (KOD=:P1) ORDER BY KOD
ENDPROC

	IF {STR [20]<>’’}  PREPARESQL SzukajPoKodzie,[20]
	IF {STR [20]=’’} PREPARESQL  SzukajWszystkich

; procedura drukująca adres
PROCEDURE PrintAdres
 if {EVAL dbAdresy:EOF=1} EXIT
 T=10,14|STR dbAdresy:Nazwa1
 T=10,18|STR dbAdresy:Kod
 T=10,22|STR dbAdresy:Miasto
 T=10,26|STR dbAdresy:Ulica
ENDPROC

;i drukuj
PAGE 0,0

;drukuj adres na pozycji 120,60
CALL PrintAdres,120,60
;do następnego rekordu
CALL dbAdresy:Next
;powtórz stronę jeśli nie koniec
if {EVAL dbAdresy:EOF=0} RepeatPage 1

END

W powyższym przykładzie program przekazuje do formularza plik danych, w którym w polu nr 20 zapisany jest warunek wyszukiwania – w tym wypadku kod pocztowy. Jeżeli pole to będzie puste, należy wydrukować wszystkie adresy, stąd też wywołujemy zapytanie SzukajWszystkich. Jeżeli użytkownik programu podał kod pocztowy, wywołujemy zapytanie SzukajPoKodzie. Zwracamy ponownie uwagę na fakt, że dla obu zapytań określiliśmy tę samą nazwę tabeli wynikowej. Dlaczego? Otóż – oba zapytania udostępniają nam inny fragment tej samej tabeli, zawierający identyczne pola. Wynika z tego, że procedura drukowania adresu jest taka sama dla obu zapytań, a więc mogłaby odwoływać się do jednej i tej samej tabeli. Określamy w tym momencie, że tabela wynikowa z obu zapytań nazywać się będzie tak samo – bo nie wystąpi sytuacja, gdy oba zapytania zostaną wykonane jednocześnie. Dzięki temu jedna procedura drukowania koperty obsłuży oba zapytania. W przeciwnym razie musielibyśmy stworzyć dwie procedury drukowania – o niemal tej samej treści, różniące się jedynie nazwą tabeli, z której pól korzystają.

11. Informacje dla programistów
Wstęp
Osobnego wyjaśnienia wymaga kwestia użycia komponentu TScriptPrinter odpowiedzialnego za generowanie raportów w programach napisanych w językach Borland Delphi oraz Borland C++. Poruszymy tu dwie kwestie: wywoływanie komponentu i zmianę jego właściwości oraz techniki przekazywania doń danych, drukowanych potem w wydrukach. Zakładamy, że użytkownik komponentu poprawnie go zainstalował w swoim środowisku programistycznym – czynność ta nie jest trudna, więc pomińmy ją milczeniem.

Użytkowanie komponentu
Po umieszczeniu komponentu TScriptPrinter na swoim formularzu możemy przystąpić do tworzenia metody drukującej raport. Zanim to się stanie, konieczne jest ustawienie kilku właściwości naszego obiektu i wywołanie na jego rzecz metod. Oto ich wyszczególnienie:

•	metoda ClearParams – powoduje wyczyszczenie listy pól danych
•	metoda AddParam(Number:Integer; Value:String) – przekazuje do raportu kolejne pole danych 
•	metoda AddTable(Table:TDataSet) – przekazuje do raportu tabelę danych
•	pole Title:String – nagłówek okienka drukowania
•	pole Description:String – opis wydruku pojawiający się w okienku drukowania
•	pole DataFile:String – zawiera nazwę pliku zawierającego tabele tekstowe (punkt 8)
•	pole ScriptFile:String – zawiera nazwę formularza wydruku do zanalizowania i wydrukowania
•	pole ShowPrintDialog:Boolean – wyświetlanie ustawień drukarki przed rozpoczęciem drukowania
•	metoda Execute – powoduje wczytanie formularza i wyświetlenie okna drukowania

Metody ClearParams oraz AddParam służą do przekazania do raportu wartości dla pól danych [nr] używanych w formularzu. W programie należy umieścić najpierw polecenie ClearParams, czyszczące wartości pól po ewentualnych poprzednich wydrukach, po czym wywołując odpowiednią ilość poleceń AddParam przekazać do formularza wartości wszystkich użytych w nim pól danych.

Metoda AddTable przekazuje do formularza już otwartą i przygotowaną tabelę danych. Z tabeli tej można korzystać w formularzu używając bezpośrednio jej nazwy. Dzięki tej możliwości nie jest konieczne korzystanie w formularzu z zapytań SQL w sytuacji, gdy sam program już otworzył i odpowiednio przetworzył bazę danych, a wydrukowanie sprowadza się do przestawienia wszystkich rekordów tej przetworzonej już bazy danych. Znacząco zwiększa to szybkość przygotowywania wydruków – gdyż program nie traci czasu na ponowne wyszukanie rekordów spełniających warunki wymagane do ich wydrukowania. Do formularza można przekazać każdy obiekt będący potomkiem obiektu TDataSet – a więc tabele TTable, zapytania TQuery i inne ewentualne źródła danych.

Pola Title oraz Description mają znaczenie wyłącznie wizualne – odpowiadają za teksty wyświetlane w okienku drukowania formularza. Warto jednak wpisać tam coś sensownego...

Pole ScriptFile to bardzo ważne pole – zawiera ono nazwę pliku formularza, który ma być użyty do wydruku. Zalecamy używanie pełnych nazw plików (włącznie ze ścieżką) – środowisko Windows jest podatne na niezauważalne dla użytkownika zmiany bieżącego katalogu. Najprościej korzystać w tym celu z funkcji ExtractFilePath(Application.ExeName), zwracającej ścieżkę do katalogu w którym znajduje się program (a więc prawdopodobnie i formularze wydruku).

Pole DataFile zawiera nazwę pliku tekstowego, w którym zapisana jest tabela tekstowa – specyficzny rodzaj bazy danych nie wymagający użycia sterowników BDE. Szczegóły na temat obsługi i przydatności tabel tekstowych – punkt 8.

Pole ShowPrintDialog zawiera informację o tym, jak program ma się zachować po wciśnięciu w okienku drukowania przycisku DRUKUJ. Jeżeli pole ma wartość FALSE (domyślnie), drukowanie od razu się rozpocznie. Jeżeli pole ma wartość TRUE, pojawi się na ekranie standardowe okienko drukowania, w którym można określić parametry wydruku lub drukarki i dopiero rozpocząć drukowanie.

Metoda Execute zbiera wszystko w jedną całość i wywołuje okienko drukowania. Wciskając w nim stosowne klawisze można wydrukować lub obejrzeć nasz formularz. Tam też można na gorąco dokonać zmian w projekcie formularza.

Przykładowy program
Poniżej - przykładowa procedura drukująca niezbyt skomplikowany wydruk dowodu księgowego:

function TfrmDowod.WydrukujDowod:Boolean;
begin
 WydrukujDowod := FALSE;

 try
   ScriptPrinter.ClearParams;
   ScriptPrinter.AddParam(1, Dane.dbDowodId.AsString);
   ScriptPrinter.AddParam(2, MiesiacRokStr(Dane.dbDowodData.Value));
   ScriptPrinter.Description := 'Dowód księgowy nr '+Dane.dbDowodNumer.AsString;
   ScriptPrinter.DataFile := '';
   ScriptPrinter.ScriptFile := ExtractFilePath(Application.ExeName) + fnDowod;
   ScriptPrinter.ShowPrintDialog := FALSE;
   ScriptPrinter.Execute;
   WydrukujDowod := TRUE;
 except
 end;
end;